/*
//依赖libevent_cpp库
需要下面写才能工作：

main()
{

	调用本库的api

	EventMgr::Ins().Dispatch();
}

*/

#pragma once
#include <string>
#include <vector>
#include <unordered_map>
#include <map>
#include "svr_util/include/singleton.h"
#include "dbProto/dbTable.h"
#include "RpcNet.h"


namespace proto {

	//为了获取lambda函数的参数1类型
	template <class Fn>
	struct Arg1OfLambda;

	template <class T, class DbTable>
	struct Arg1OfLambda<void(T::*)(const DbTable*) const>
	{
		using Arg1 = DbTable;
	};


	//db driver 接口
	class Dbproxy: public Singleton<Dbproxy>
	{
		using RevQueryFun = std::function<void(const std::string&)>;
		RpcNetClient gClient;
		std::map<uint16_t, RevQueryFun> m_id2RevQueryFun;
	public:
		//@onInitOk 初始化完成回调
		void Init(const std::string& ip, uint16_t port, std::function<void()> onInitOk = nullptr);
		void Insert(const proto::BaseTable &data, std::function<void (bool)> ret = nullptr);
		void Del(const proto::BaseTable& data, std::function<void(bool)> ret = nullptr);
		template<class Cb>
		void QueryCond(const std::string& cond, Cb ret)
		{
			typedef class Arg1OfLambda<decltype(&decltype(ret)::operator())>::Arg1 DbTable;
			auto f = [ret](const std::string& revData)
			{
				if (revData.empty())
				{
					ret(nullptr);
					return;
				}
				std::unique_ptr<BaseTable> pTable = TableCfg::Ins().Unpack(revData);
				L_COND_V(nullptr != pTable);
				if (const DbTable* pDbTable = dynamic_cast<const DbTable*>(pTable.get()))
				{
					ret(pDbTable);
				}
				else
				{
					LERROR("Table type no match. tableId=", pTable->TableId());
					ret(nullptr);
				}
			};
			static DbTable id;
			gClient.Call(f, "QueryCond", id.TableId(), cond);
		}
		
		//请求一次只能获取一项数据
		//推荐，高效函数
		//@ret 通过回调函数，获得内容打包字符串

		//@return 查询失败返回空字符串
		/*
			example:
			static PlayerDb player;
			auto f=[&player](const std::string& data){
				TableCfg::Ins().UnpackForObj(player, data);
			};
			Dbproxy::Ins().QueryCond(player.GetTableId(), "id= 33 and name= 'Jack'", f);
		*/
		void QueryCondRaw(uint16_t tableId, const std::string& cond, std::function<void(const std::string&)> ret);
		//查询一行数据部分字段
		//@return 查询失败返回空字符串
		void QueryCondPartly(uint16_t tableId, const std::string& cond, const std::vector<std::string>& vecFieldName, std::function<void(const std::string&)> ret);

		//@retCb 注册返回QueryCondForMore结果的函数.  void(const std::string& data) data.empty() 表示最后一次返回。
		//@table_id  BaseTable::TableId()
		//@cond 条件，sql语法
		//@限制数量 0 表示不限制
		//获取结果参考 RegQueryCondForMore 函数
		/*
			example:
			void RetDb(const std::string& data)
			{
				PlayerDb player;
				TableCfg::Ins().UnpackForObj(player, data);
				...
			}

			...
			Dbproxy::Ins().RpcQueryCondForMore(player.GetTableId(), "id== 33", RetDb);
		*/
		void QueryCondForMore(uint16_t tableId, const std::string& cond, void(*retCb)(const std::string&), uint32_t limitNum = 0);
		void Update(const proto::BaseTable& obj);//更新数据，没填值的字段不会更新
		void Sql(const std::string &sql);

	private:
		void RevQueryCondForMore(uint16_t tableId, const std::string& data);
	};
}